home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.02 Feb 95 / Yenta / SendWindowƒ / CPPSendWindow.cp next >
Encoding:
Text File  |  1996-04-04  |  16.5 KB  |  539 lines  |  [TEXT/KAHL]

  1. /***************************************************** IMPLEMENTATION
  2.     DATE:    9/26/93
  3.     AUTHOR: Eric R. Rosé
  4.  
  5.     CLASS:  CPPSendWindow
  6.     
  7.     SUPERCLASS: CPPWindow
  8.     
  9.         This C++ class manages the NetApp Send window
  10.     
  11. ********************************************************************/
  12.  
  13. #include "CPPSendWindow.h"
  14. #include "CPPMessageWindow.h"
  15. #include <CPPPictButton.h>
  16. #include <CPPButton.h>
  17. #include <CPPCheckBox.h>
  18. #include <CPPStaticText.h>
  19. #include "CPPZoneList.h"
  20. #include "CPPUserList.h"
  21. #include "CPPVisualList.h"
  22. #include "CPPWatchWriteTask.h"
  23. #include <CPPText.h>
  24. #include <CPPConnectTask.h>
  25. #include <CPPSound.h>
  26. #include <CPPMaBell.h>
  27. #include <CPPWriteTask.h>
  28. #include <CPPNode411.h>
  29. #include <CPPStringList.h>
  30. #include <CPPZone411.h>
  31. #include <CPPNodeInfo.h>
  32. #include <CPPVisualObjectList.h>
  33. #include <CPPDRequest.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <script.h>
  37. #include "MyGlobals.h"
  38. #include <ConvertTools.h>
  39. #include <StringTools.h>
  40. #include <ToolboxTools.h>
  41. #include <MemoryTools.h>
  42.  
  43. #define        SendWindowID    200
  44. #define        kSendButton        -1
  45. #define        kZoneButton        -2
  46. #define        kUserListClick    -3
  47. #define        kZoneListClick    -4
  48.  
  49. extern    StringPtr        gReplyString;
  50. extern    RGBColor        RGBRed;
  51. extern    CPPZoneList        *gZoneList;    // pointer to the send dialog's zone list
  52. extern    CPPUserList        *gUserList;    // pointer to the send dialog's user list
  53. extern    CPPMaBell        *gMaBell;
  54. extern    CPPTaskManager    *gSlaveDriver;
  55. extern    CPPNodeInfo     *gOurIdentity;
  56. extern    CPPList         *gTalkText;
  57. extern    PPCPortRefNum    gOurPort;
  58. extern    PrefsData        gPrefsInfo;
  59. extern    CPPSendWindow    *gSendWindow;
  60. extern    CPPMessageWindow    *gMessageWindow;
  61. extern    CPPSound        *gIncomingSound;
  62. extern    CPPSound        *gLogonSound;
  63. extern    StringPtr        gAppName;
  64.  
  65. /*-----------------------------------------------------------------*/
  66.  
  67.     void ProcessNodeLookupResults    (CPPObject *TheTask);
  68.     void ProcessZoneLookupResults    (CPPObject *TheTask);
  69.  
  70. /*-----------------------------------------------------------------*/
  71.  
  72.     void ProcessZoneLookupResults    (CPPObject *TheTask)
  73.     /* called whenever our zone lookup task completes, this routine */
  74.     /* simply displays the number of zones found; since the visual */
  75.     /* ZoneList depends directly on the lookup task's data list, */
  76.     /* all visual updating will have already taken place */
  77.     {
  78.         CPPZone411    *LookupTask = (CPPZone411 *)TheTask;
  79.         long        numItems = 0;
  80.         Boolean        BTemp;
  81.         char        NewMessage[255];
  82.         
  83.         if (LookupTask)
  84.           numItems = LookupTask->NumZonesFound(&BTemp);
  85.         
  86.         sprintf (NewMessage, "Found %d zone%c.",  numItems,
  87.                  (numItems == 1) ? ' ' : 's');
  88.         gSendWindow->SetStatusMessage(Data2PString(NewMessage, 
  89.                                       strlen(NewMessage)), FALSE);
  90.           
  91.     }
  92. /*-----------------------------------------------------------------*/
  93.  
  94.     void ProcessNodeLookupResults    (CPPObject *TheTask)
  95.     /* called whenever a node lookup task completes, this routine */
  96.     /* adds each user in turn to the user list;                 */
  97.     /* NOTE:  Only the unique users will actually be added -  */
  98.     /*        see CPPUserList::AddNewUser */
  99.     {
  100.         CPPNode411    *LookupTask = (CPPNode411 *)TheTask;
  101.         Boolean        BTemp, UA = FALSE;
  102.         long        before, numUnique;
  103.         char        NewMessage[255];
  104.         
  105.         before = gSendWindow->UserList->GetNumItems();
  106.         
  107.         for (long i = 1; i <= LookupTask->NumNodesFound(&BTemp); i++)
  108.           UA = gUserList->AddNewUser(LookupTask->NthNode (i, FALSE)) || UA;
  109.         if (UA)
  110.           if (gPrefsInfo.playLogon)
  111.             gLogonSound->PlaySound(TRUE);
  112.           
  113.         numUnique = gSendWindow->UserList->GetNumItems() - before;
  114.         if (numUnique)
  115.           sprintf (NewMessage, "Found %d new user%c.", numUnique, 
  116.                       (numUnique == 1) ? ' ' : 's');
  117.         else
  118.           sprintf (NewMessage, "No new users were found.");
  119.         gSendWindow->SetStatusMessage(Data2PString (NewMessage, strlen(NewMessage)), FALSE);
  120.     }
  121.  
  122. /*-----------------------------------------------------------------*/
  123. /*------------------------ PUBLIC METHODS -------------------------*/
  124. /*-----------------------------------------------------------------*/
  125.  
  126.     CPPSendWindow::CPPSendWindow (CPPWindowManager *theManager) :
  127.                     CPPWindow (theManager, SendWindowID)
  128.     {
  129.         StringPtr    TempString, STemp;
  130.         Rect    tempRect;
  131.         Point    tempPt;
  132.         CPPStaticText    *ST = NULL;
  133.                                 
  134.     // create the list where we will store all the users we know about
  135.         this->UserListData = new CPPObjectList();
  136.  
  137.     // create the lookup tasks
  138.         NodeLookup = new CPPNode411 (gSlaveDriver, 25, FALSE);
  139.         ZoneLookup = new CPPZone411 (gSlaveDriver, gMaBell, 60, FALSE);
  140.                                 
  141.     // place all of the static text items
  142.         SetRect (&tempRect, 32, 14, 136, 30);
  143.         ST = new CPPStaticText ((CPPWindow *)this, &tempRect, 129);
  144.     
  145.         SetRect (&tempRect, 222, 14, 346, 30);
  146.         ST = new CPPStaticText ((CPPWindow *)this, &tempRect, 130);
  147.     
  148.         SetRect (&tempRect, 14, 153, 118, 250);
  149.         ST = new CPPStaticText ((CPPWindow *)this, &tempRect, 131);
  150.  
  151.         SetRect (&tempRect, 14, 288, 382, 302);
  152.         Status = new CPPStaticText ((CPPWindow *)this, &tempRect, 
  153.                       133, geneva, 9, teJustLeft, italic, &RGBRed);
  154.  
  155.     // place the zone and user lists
  156.         SetRect(&tempRect, 14, 35, 136, 148);
  157.         ZoneList = new CPPZoneList ((CPPWindow *)this, &tempRect,
  158.                                     (CPPDArray *)(ZoneLookup->GetFoundList()),
  159.                                     FALSE);
  160.         ZoneList->SetCommand (kZoneListClick);
  161.         gZoneList = ZoneList;
  162.         
  163.         SetRect (&tempRect, 222, 35, 382, 148);
  164.         UserList = new CPPUserList ((CPPWindow *)this, &tempRect,
  165.                                     this->UserListData, TRUE);
  166.         UserList->SetCommand (kUserListClick);
  167.         gUserList = UserList;
  168.         
  169.     // place the textedit area
  170.         SetRect (&tempRect, 14, 170, 382, 244);
  171.         SendText = new CPPText ((CPPWindow *)this, &tempRect, 
  172.                                 &tempRect, 32000, FALSE, TRUE);
  173.         ARWarning = new CPPStaticText((CPPWindow *)this, &tempRect,
  174.                                       "\pAUTOREPLY ON:", geneva,
  175.                                       9, teJustCenter, bold, &RGBRed,
  176.                                       FALSE, TRUE, FALSE);
  177.         
  178.     // place the 'echo' checkbox
  179.         SetRect (&tempRect, 14, 262, 204, 278);
  180.         CBEcho = new CPPCheckBox ((CPPWindow *)this, 128, TRUE);
  181.         
  182.     // place the 'load zones' picture button
  183.         tempPt.h = 14; tempPt.v = 14;
  184.         PBLoadZones = new CPPPictButton((CPPWindow *)this, 128, tempPt, 
  185.                                         kUseDarken);
  186.         PBLoadZones->SetCommand (kZoneButton);
  187.  
  188.     // place the default 'send' button
  189.         SetRect (&tempRect, 282, 260, 381, 280);
  190.         SendButton = new CPPButton((CPPWindow *)this, 132, TRUE);
  191.         SendButton->SetCommand (kSendButton);
  192.                 
  193.         MakeTarget (SendText);
  194.     
  195.         // start by loading a list of zones
  196.         ZoneLookup->StartZoneLookup(ProcessZoneLookupResults);
  197.     }
  198.     
  199. /*-----------------------------------------------------------------*/
  200.  
  201.     CPPSendWindow::~CPPSendWindow (void)
  202.     {
  203.         // let the standard dispose routine get rid of the window items
  204.     }
  205.  
  206. /*-----------------------------------------------------------------*/
  207.  
  208.     char    *CPPSendWindow::ClassName (void)
  209.     {
  210.         return "CPPSendWindow";
  211.     }
  212.  
  213. /*-----------------------------------------------------------------*/
  214.  
  215.     Boolean    CPPSendWindow::DoCommand (short commandID)
  216.     /* handle commands specific to our window */
  217.     {
  218.         Boolean    result = TRUE;
  219.         StringPtr    ZoneName;
  220.         Str255    newMessage;
  221.         Str32    TypeStr;
  222.         long    whichCell;
  223.         
  224.         switch (commandID) {
  225.         
  226.             case kUserListClick :    // send text to selected users
  227.             case kSendButton :    // send text to selected users
  228.                 DoSendButton();
  229.                 break;
  230.         
  231.             case kZoneButton :    // re-load the list of zones
  232.                 ZoneLookup->StartZoneLookup(ProcessZoneLookupResults);
  233.                 
  234.                 // let the user know we are scanning
  235.                 SetStatusMessage(String2String ("\pScanning network for available zones"), FALSE);
  236.                 break;
  237.         
  238.             case kZoneListClick :    // scan zone for new users
  239.                 if (ZoneList->FirstSelectedCell (&whichCell))
  240.                   {
  241.                     ZoneName = (*this->ZoneList)[whichCell];
  242.                     if (ZoneName)
  243.                       {
  244.                           PStrCat (32, TypeStr, 2, "\p≈•", gAppName);
  245.                         this->NodeLookup->StartNodeLookup
  246.                                       ("\p=", TypeStr, ZoneName, 50,
  247.                                       ProcessNodeLookupResults);
  248.                       }
  249.                 
  250.                     // let the user know we are scanning 
  251.                     PStrCat (255, newMessage, 3, "\pScanning zone '", ZoneName, 
  252.                              "\p' for other Yentot.");
  253.                     SetStatusMessage(newMessage, TRUE);
  254.                   }
  255.                 break;
  256.         
  257.             default:
  258.                 result = CPPWindow::DoCommand(commandID);
  259.                 break;
  260.         }
  261.         
  262.         return result;
  263.     }
  264.  
  265.  
  266. /*-----------------------------------------------------------------*/
  267.  
  268.     void    CPPSendWindow::SetStatusMessage (StringPtr newMessage, Boolean makeCopy)
  269.     {
  270.         if (newMessage)
  271.           this->Status->SetitsString(newMessage, makeCopy);
  272.     }
  273.  
  274. /*-----------------------------------------------------------------*/
  275. /*--------------------- PROTECTED METHODS -------------------------*/
  276. /*-----------------------------------------------------------------*/
  277.  
  278.     Boolean    CPPSendWindow::DoUserKey (EventRecord *theEvent)
  279.     {
  280.         char theKey;
  281.         CPPList    *TempList;
  282.         StringPtr    STemp;
  283.         char    s[25];
  284.         
  285.  
  286.         theKey = theEvent->message & charCodeMask;
  287.         if (!(theEvent->modifiers & cmdKey))
  288.           {
  289.               switch (theKey) {
  290.                   case kTab :
  291.                       if (ShiftKeyDown(theEvent->modifiers))
  292.                         {MakePreviousTarget(); return TRUE;}
  293.                       else
  294.                         {MakeNextTarget(); return TRUE;}
  295.                       break;
  296.  
  297.                   case kEnter :
  298.                       if (SendButton)
  299.                         SendButton->SimulateClick();
  300.                       break;
  301.                   default:
  302.                       return CPPWindow::DoUserKey (theEvent);
  303.                       break;
  304.             }
  305.           }
  306.     }
  307.     
  308. /*-----------------------------------------------------------------*/
  309.  
  310.     void    CPPSendWindow::RefreshItemStates()
  311.     /* this routine is called whenever an event occurs so that */
  312.     /* the window can check to see if any of the objects in it */
  313.     /* should be enabled/disabled, etc.  For example, if a button */
  314.     /* should only be active when certain conditions are true, */
  315.     /* you could use this routine to activate/deactivate it */
  316.     {
  317.         Str255    STemp;
  318.         GrafPtr    SavePort;
  319.         long    whichCell;
  320.         
  321.         GetPort (&SavePort);
  322.         SetPort (this->theWindow);
  323.         
  324.         // update the text/autoreply message
  325.         if (gReplyString)
  326.           {
  327.               if (SendText->IsVisible())
  328.                 {
  329.                     if (GetTarget() == SendText)
  330.                       this->MakeNextTarget();
  331.                     SendText->MakeVisible(FALSE);
  332.                     PStrCat (255, STemp, 2, "\pAUTOREPLY ON:\r", gReplyString);
  333.                     ARWarning->SetitsString(STemp, TRUE);
  334.                     ARWarning->MakeVisible(TRUE);
  335.                 }
  336.           }
  337.         else
  338.           if (!SendText->IsVisible())
  339.             {
  340.               ARWarning->MakeVisible(FALSE);
  341.               SendText->MakeVisible(TRUE);
  342.               this->MakeTarget(SendText);
  343.             }
  344.             
  345.         // update the enabled/disabled state of the 'Send' button
  346.         if (UserList->FirstSelectedCell(&whichCell) && (SendText->GetTextLen()))
  347.           {
  348.               if (!SendButton->IsEnabled())
  349.                 SendButton->EnableButton(TRUE);
  350.           }
  351.         else
  352.           {
  353.               if (SendButton->IsEnabled())
  354.                 SendButton->EnableButton(FALSE);
  355.           }
  356.             
  357.         SetPort (SavePort);
  358.     }
  359.  
  360. /*-----------------------------------------------------------------*/
  361.  
  362.     void    CPPSendWindow::DoSendButton(void)
  363.     /* handle the pressing of the 'send' button by sending a message */
  364.     /* containing our address and the text in the 'send text' area */
  365.     /* to each of the hilighted users */
  366.     {
  367.         long    NumToSendTo = this->UserList->NumSelectedCells();
  368.         Ptr        OurIDStream = gOurIdentity->InfoToStream();
  369.         Handle    Text2Send = this->SendText->GetTheText();
  370.         long    TextLen = this->SendText->GetTextLen();
  371.         Ptr        TempPtr = NULL;
  372.         long    whichUser = 0;
  373.         Str32    theTime;
  374.         Str255    newMessage;
  375.         OSErr    ErrCode;
  376.         CPPNodeInfo            *UserData = NULL;
  377.         CPPWatchWriteTasks    *WatchTask;
  378.         CPPConnectTask        *CTask;
  379.         
  380.         // exit if there is only 1 user or no text to send
  381.         if (!(TextLen && NumToSendTo))
  382.           return;
  383.         
  384.         /* create a ptr large enough to hold our ID and the text */
  385.         TempPtr = NewPtr(TextLen + GetPtrSize(OurIDStream));
  386.         if ((ErrCode = MemError()) != noErr)
  387.           ErrorAlert(ErrCode, "\pCan't send message.");
  388.         else
  389.           {
  390.               BlockMove (OurIDStream, TempPtr, GetPtrSize(OurIDStream));
  391.               BlockMove (*Text2Send, TempPtr+GetPtrSize(OurIDStream), TextLen);
  392.             DisposPtr (OurIDStream);
  393.             
  394.             // if 'echo to message window' is checked, add a copy of 
  395.             // the text to our incoming message queue
  396.             if (CBEcho->GetValue())
  397.               gTalkText->AppendItem (Ptr2Ptr(TempPtr));
  398.             
  399.             // send text to each hilighted user
  400.             while (this->UserList->NextSelectedCell(&whichUser))
  401.               {
  402.                   UserData = (CPPNodeInfo *)((*this->UserList)[whichUser]);
  403.                   if (UserData && !(UserData->Equals(gOurIdentity)))
  404.                     SendToUser (TempPtr, NumToSendTo == 1, UserData);
  405.               }
  406.  
  407.             // if there is more than one user to write to, we have to spawn
  408.             // a task to wait for the write tasks to complete and then
  409.             // dispose of 'TempPtr'
  410.             if (NumToSendTo != 1)
  411.               {
  412.                 WatchTask = new CPPWatchWriteTasks (gSlaveDriver, 60);
  413.                 WatchTask->StartWatchTask(TempPtr);
  414.               }
  415.  
  416.             // display a message so they know the data was sent
  417.             CurrentTimeString (TRUE, theTime, 32);
  418.             PStrCat (255, newMessage, 2, "\pMessage(s) sent at ",theTime);
  419.             SetStatusMessage(newMessage, TRUE);
  420.           }
  421.         
  422.     }
  423.     
  424. /*-----------------------------------------------------------------*/
  425.  
  426.     void    CPPSendWindow::SendToUser(Ptr Text, Boolean ownsData, CPPNodeInfo *SendTo)
  427.     /* send the passed in Text to the specified user;  if ownsData is TRUE, */
  428.     /* let the write task dispose of the data */
  429.     {
  430.         CPPWriteTask    *TheTask;
  431.     
  432.         // Create a write task and have it open the connection and
  433.         // send the data to the other user
  434.           TheTask = new CPPWriteTask (gSlaveDriver, 25, TRUE);
  435.           TheTask->StartWriteTask (gOurPort, SendTo, Text, ownsData, NULL, 
  436.                                    (OSType)'TEXT', (OSType)'YntA');              
  437.     }
  438.     
  439. /*-----------------------------------------------------------------*/
  440.  
  441.     void    CPPSendWindow::ProcessMessageQ (void)
  442.     /* if there are any entries in gTalkText, extract the */
  443.     /* first one and put its data in the message window */
  444.     {
  445.         Ptr        MessageText, MessageStart;
  446.         long    MessageLen;
  447.         Str255    Header;
  448.         Str63    TimeString, IDString;
  449.         long    i = 1;
  450.         CPPNodeInfo    *SendersAddress;
  451.         StringPtr    ObjStr, TypeStr, ZoneStr;
  452.         short    OldTypeStrLen;
  453.         
  454.         // exit if there are no items in the list
  455.         if (gTalkText->GetNumItems() == 0)
  456.           return;
  457.         
  458.         // get the first item in the list; exit if empty
  459.         MessageText = (*gTalkText)[1];
  460.         if (!MessageText) return;
  461.         MessageLen = GetPtrSize(MessageText);
  462.         
  463.         // Construct a header for the message which tells who sent it and when
  464.         // it arrived:
  465.         // 1. Get the user's name and address out of the message
  466.         SendersAddress = (CPPNodeInfo *)StreamToInfo (MessageText, &MessageStart);
  467.         // 2. Build a string in the format UserName@ZoneName
  468.         SendersAddress->GetNodeName(&ObjStr, &TypeStr, &ZoneStr);
  469.         while (((TypeStr[i] & 0x00FF) != 0xA5) && (i <= MessageLen))
  470.           i++;
  471.         OldTypeStrLen = TypeStr[0];
  472.         TypeStr[0] = i-1;
  473.         // 3. Get a string which specifies the arrival time
  474.         CurrentTimeString (TRUE, TimeString, 32);
  475.         // 4. Construct the header
  476.         PStrCat (255, Header, 7, "\p\r<Message received from ", TypeStr,
  477.                  "\p@", ZoneStr, "\p at ", TimeString, "\p>\r•");
  478.         TypeStr[0] = OldTypeStrLen;
  479.         
  480.         // 1. Insert the header
  481.         gMessageWindow->InsertTextPtr ((Ptr)&Header[1], *Header, 32767, TRUE);
  482.         // 2. insert the text of the message
  483.         gMessageWindow->InsertTextPtr(MessageStart, MessageLen - 
  484.                                       (long)(MessageStart - MessageText), 
  485.                                       32767, FALSE);
  486.     
  487.         if (gPrefsInfo.playMessage && !(SendersAddress->Equals(gOurIdentity)))
  488.           gIncomingSound->PlaySound(TRUE);
  489.     
  490.         // now, call a method to handle the autoreply and place the
  491.         // user's name in the list of known users.
  492.         if (!(SendersAddress->Equals(gOurIdentity)))
  493.           GotNewMessage (SendersAddress);
  494.     
  495.         DisposPtr(MessageText);
  496.         
  497.         gTalkText->DeleteItem(1, TRUE);
  498.     }
  499.  
  500. /*-----------------------------------------------------------------*/
  501.  
  502.     void    CPPSendWindow::GotNewMessage (CPPNodeInfo *FromWhom)
  503.     // check to see whether the person we received the message from
  504.     // is in the user list.  If not, search the network for him
  505.     {
  506.         Ptr            TempPtr, OurIDStream;
  507.         OSErr        ErrCode;
  508.  
  509.           // check to see if 'autoreply' is on; if so, send him
  510.           // a message in response
  511.           if (gReplyString)
  512.             {                
  513.             // Create a string which has our name and address in it, so that
  514.             // the other user can add us to his list if he doesn't know about us
  515.             OurIDStream = gOurIdentity->InfoToStream();
  516.             
  517.             // create a pointer big enough to hold our address, plus the data in
  518.             // the reply string
  519.             TempPtr = NewPtr (GetPtrSize(OurIDStream) + gReplyString[0]);
  520.             if ((ErrCode = MemError()) == noErr)
  521.               {              
  522.                   BlockMove (OurIDStream, TempPtr, GetPtrSize(OurIDStream));
  523.                   BlockMove (gReplyString+1, TempPtr+GetPtrSize(OurIDStream), *gReplyString);
  524.                 DisposPtr (OurIDStream);
  525.                 
  526.                 // send the autoreply to the user who sent us the message
  527.                 SendToUser (TempPtr, TRUE, FromWhom);
  528.                 }
  529.           }
  530.           
  531.         // Add the user to the list; if they are already in the list, nothing
  532.         // will happen
  533.         if (this->UserList->AddNewUser(FromWhom))
  534.           if (gPrefsInfo.playLogon)
  535.             gLogonSound->PlaySound(TRUE);
  536.     }
  537.     
  538. /*-----------------------------------------------------------------*/
  539.